home *** CD-ROM | disk | FTP | other *** search
- /*
- * TOOLS.C
- *
- ****************************************************************************
- * *
- * part of: *
- * TCP/IP kernel for NCSA Telnet *
- * by Tim Krauskopf *
- * *
- * National Center for Supercomputing Applications *
- * 152 Computing Applications Building *
- * 605 E. Springfield Ave. *
- * Champaign, IL 61820 *
- * *
- * Copyright (c) 1987, Board of Trustees of the University of Illinois *
- * *
- ****************************************************************************
- *
- * Portions of the driver code that are not specific to a particular protocol
- *
- */
- #include <stdio.h>
- #include "protocol.h"
- #include "data.h"
- #include "mactools.h"
- #include "tcp.h"
-
- #include <Events.h>
- #include <ToolUtils.h> /* BYU 2.4.16 MPW - for GetIndString() */
- #include <String.h>
- #include <Strings.h> /* BYU 2.4.16 MPW - for p2cstr() */
-
- extern short slip_connection; /* BYU 2.4.15 */
-
- /***************************************************************************/
- /* enqueue
- * add something to a TCP queue. Used by both 'write()' and tcpinterpret
- * WINDOWSIZE is the size limitation of the advertised window.
- */
- int enqueue
- (
- struct window *wind,
- char *buffer,
- int nbytes
- )
- {
- int i;
-
- i = WINDOWSIZE - wind->contain;
- if (i <= 0 || nbytes == 0)
- return(0); /* no room at the inn */
-
- if (nbytes > i)
- nbytes = i;
-
- i = wind->where - wind->endlim; /* room at end */
- i += WINDOWSIZE;
-
- if (i < nbytes) {
- movebytes(wind->endlim,buffer,i);
- movebytes(wind->where,(char *)(buffer+i),nbytes-i);
- wind->endlim = wind->where + nbytes - i;
- }
- else {
- movebytes(wind->endlim,buffer,nbytes); /* fits in one chunk */
- wind->endlim += nbytes;
- }
- wind->contain += nbytes; /* more stuff here */
-
- return(nbytes);
-
- }
-
- /*************************************************************************/
- /* dequeue
- * used by read, this copies data out of the queue and then
- * deallocates it from the queue.
- * cpqueue and rmqueue are very similar and are to be used by tcpsend
- * to store unacknowledged data.
- *
- * returns number of bytes copied from the queue
- */
- int dequeue
- (
- struct window *wind,
- char *buffer,
- int nbytes /* maximum number to copy out */
- )
- {
- int i;
-
- if (wind->contain == 0)
- return(0);
-
- if (wind->contain < nbytes)
- nbytes = wind->contain;
-
- i = wind->endbuf - wind->base;
-
- if (i <= nbytes) {
- movebytes(buffer,wind->base,i);
- movebytes((char *)(buffer+i),wind->where,nbytes-i);
- wind->base = wind->where + nbytes-i;
- }
- else {
- movebytes( buffer, wind->base, nbytes);
- if (wind->contain == nbytes)
- wind->base = wind->endlim = wind->where;
- else
- wind->base += nbytes;
- }
-
- wind->contain -= nbytes;
-
- return(nbytes);
-
- }
-
- #ifdef notneeded
- /**************************************************************************/
- /* cpqueue
- * does the same thing as dequeue, but does not deallocate the data
- * used when transmitting TCP data. When the data is ACKed, then
- * rmqueue is called to deallocate the correct amount of data.
- */
- cpqueue(wind,buffer,nbytes)
- struct window *wind;
- char *buffer;
- int nbytes; /* maximum number to copy out */
- {
- int i;
-
- if (wind->contain == 0)
- return(0);
-
- if (wind->contain < nbytes)
- nbytes = wind->contain;
-
- i = wind->endbuf - wind->base;
-
- if (i < nbytes) {
- movebytes(buffer,wind->base,i);
- movebytes((char *)(buffer+i),wind->where,nbytes-i);
- }
- else
- movebytes( buffer, wind->base, nbytes);
-
- return(nbytes);
-
- }
- #endif
-
- /**************************************************************************/
- /* rmqueue
- * does the queue deallocation that is left out of cpqueue
- *
- * rmqueue of WINDOWSIZE or greater bytes will empty the queue
- */
- int rmqueue
- (
- struct window *wind,
- int nbytes /* number to remove */
- )
- {
- int i;
-
- if (wind->contain < nbytes)
- nbytes = wind->contain;
-
- i = wind->endbuf - wind->base;
-
- if (i <= nbytes)
- wind->base = wind->where+nbytes-i;
- else {
- if (wind->contain == nbytes)
- wind->base = wind->endlim = wind->where;
- else
- wind->base += nbytes;
- }
-
- wind->contain -= nbytes;
-
- return(nbytes);
-
- }
-
-
- /************************************************************************/
- /* comparen
- * Take n bytes and return identical (true=1) or not identical (false=0)
- *
- * Could be written in assembler for improved performance
- */
- int comparen
- (
- uint8 *s1,
- uint8 *s2,
- register int n
- )
- {
-
- while (n--)
- if (*s1++ != *s2++)
- return(0);
-
- return(1);
-
- }
-
- /***********************************************************************/
- /* netgetevent
- * Retrieves the next event (and clears it) which matches bits in
- * the given mask. Returns the event number or -1 on no event present.
- * Also returns the exact class and the associated integer in reference
- * parameters.
- *
- * The way the queue works:
- * There is always a dummy record pointed to by nnelast.
- * When data is put into the queue, it goes into nnelast, then nnelast
- * looks around for another empty one to obtain.
- * It looks at nnefree first, then bumps one from nnefirst if necessary.
- * When data is retrieved, it is searched from nnefirst to nnelast.
- * Any freed record is appended to nnefree.
- */
- int netgetevent
- (
- uint8 mask,
- int *retclass,
- int *retint
- )
- {
- int i,j;
-
- i = j = nnefirst;
-
- while (i != nnelast) {
- if (mask & nnq[i].eclass) {
- if (i == nnefirst)
- nnefirst = nnq[nnefirst].next; /* step nnefirst */
- else
- nnq[j].next = nnq[i].next; /* bypass record i */
-
- nnq[i].next = nnefree;
- nnefree = i; /* install in free list */
- *retint = nnq[i].idata;
- *retclass = nnq[i].eclass;
- return(nnq[i].event);
- }
- j = i;
- i = nnq[i].next;
- }
-
- return(0);
-
- }
-
- /***********************************************************************/
- /* netputevent
- * add an event to the queue.
- * Will probably get the memory for the entry from the free list.
- * Returns 0 if there was room, 1 if an event was lost.
- */
- int netputevent
- (
- int class,
- int what,
- int dat
- )
- {
- int i;
-
- i = nnelast;
- nnq[i].eclass = class; /* put data in */
- nnq[i].event = what;
- nnq[i].idata = dat;
-
- if (nnefree >= 0) { /* there is a spot in free list */
- nnq[i].next = nnelast = nnefree;
- nnefree = nnq[nnefree].next; /* remove from free list */
- return(0);
- }
- else {
- nnq[i].next = nnelast = nnefirst;
- nnefirst = nnq[nnefirst].next; /* lose oldest event */
- return(1);
- }
- }
-
- /***************************************************************************/
- /* netputuev
- * put a unique event into the queue
- * First searches the queue for like events
- */
- int netputuev
- (
- int class,
- int what,
- int dat
- )
- {
- int i;
-
- i = nnefirst;
- while (i != nnelast) {
- if (nnq[i].idata == dat && nnq[i].event == what &&
- nnq[i].eclass == class)
- return(0);
- i = nnq[i].next;
- }
-
- return(netputevent(class,what,dat));
-
- }
-
- /************************************************************************/
- /* netposterr
- * place an error into the event q
- * Takes the error number and puts it into the error structure
- */
- void netposterr
- (
- int num
- )
- {
-
- if (netputevent(ERRCLASS,ERR1,num))
-
- netputuev(ERRCLASS,ERR1,501); /* only if we lost an event */
- }
-
- /************************************************************************/
- /* transq
- *
- * Needed for TCP, not as general as cpqueue,
- * but is required for efficient uploading
- *
- * Transmit the entire queue (window) to the other host without expecting
- * any sort of acknowledgement.
- *
- */
- int transq
- (
- struct port *prt
- )
- {
- uint bites;
- int i,j,n;
- struct window *wind;
- uint32 saveseq;
- uint8 *endb,*whereb,*baseb;
-
- if (prt == NULL) {
- nnerror(406); /* NULL port for trans */
- return(-1);
- }
-
- wind = &prt->out;
- /*
- * find out how many bytes the other side will allow us to send (window)
- */
- bites = wind->size;
- if (wind->contain < bites)
- bites = wind->contain;
-
- /*
- * set up the tcp packet for this, ACK field is same for all packets
- */
- prt->tcpout.t.ack = longswap(prt->in.nxt);
- /*
- * any more flags should be set?
- */
- if (wind->push) { /* is push indicator on? */
- prt->tcpout.t.flags |= TPUSH;
- wind->push = 0;
- }
-
- if ((bites <= 0) || prt->state != SEST) { /* if no data to send . . . */
- tcpsend(prt,0); /* just a retransmission or ACK */
- return(0);
- }
-
- /*
- * we have data to send, get the correct sequence #'s
- */
- saveseq = wind->nxt;
-
- whereb = wind->where;
- endb = wind->endbuf;
- baseb = wind->base;
- /*
- * in a loop, transmit the entire queue of data
- */
- for (i=0 ; i < bites; i += prt->sendsize) {
- n = prt->sendsize;
- if (i + n > bites)
- n = bites - i;
-
- j = endb - baseb;
-
- if (j < n) {
- movebytes(prt->tcpout.x.data,baseb,j);
- movebytes((char *)(prt->tcpout.x.data+j),whereb,n-j);
- baseb = whereb + n-j;
- }
- else {
- movebytes( prt->tcpout.x.data, baseb, n);
- baseb += n;
- }
-
- tcpsend(prt,n); /* send it */
- wind->nxt += n;
- }
-
- wind->nxt = saveseq; /* get back first seq # */
-
- return(0);
- } /* transq */
-
- /************************************************************************/
- /* netsleep
- * sleep, while demuxing packets, so we don't miss anything
- *
- */
- int netsleep
- (
- int n
- )
- {
- int i,nmux,redir;
- int32 t,gt,start;
- struct port *p;
- uint8 *pc;
-
- redir = 0;
- start = time(NULL);
-
- if (n)
- t = start + n*TICKSPERSEC;
- else
- t = start;
-
- do {
- nmux = demux(1); /* demux all packets */
-
- /*
- * if there were packets in the incoming packet buffer, then more might
- * have arrived while we were processing them. This gives absolute priority
- * to packets coming in from the network.
- */
- if (nmux)
- continue;
-
- if (IREDIR == netgetevent(ICMPCLASS,&i,&i))
- redir = 1;
- /*
- * Check each port to see if action is necessary.
- * This now sends all Ack packets, due to p->lasttime being set to 0L.
- * Waiting for nmux == 0 for sending ACKs makes sure that the network
- * has a much higher priority and reduces the number of unnecessary ACKs.
- */
- gt = time(NULL);
-
- for (i=0; i < NPORTS; i++) {
- p = portlist[i];
-
- if ((p->type == 1) && !slip_connection) /* BYU 2.4.15 */
- continue; /* BYU 2.4.15 */
-
- if ((p != NULL) && (p->state > SLISTEN)) {
-
- if (!p->out.lasttime)
- transq(p); /* takes care of all ACKs */
-
- else if ((p->out.contain > 0) || (p->state > SEST)) {
- /*
- * if a retransmission timeout occurs, exponential back-off.
- * This number returns toward the correct value by the RTT measurement
- * code in ackcheck.
- *
- * fix: 5/12/88, if timer was at MAXRTO, transq didn't get hit - TK
- */
- if ((p->out.lasttime + p->rto < gt)) {
- if (p->rto < MAXRTO)
- p->rto <<= 1; /* double it */
- transq(p);
- }
- }
-
- if ((p->out.lasttime + POKEINTERVAL < gt) &&
- (p->state == SEST))
- transq(p);
- /*
- * check to see if ICMP redirection occurred and needs servicing.
- * If it needs servicing, try to get the new hardware address for the new
- * gateway. If an arp was sent during getdlayer, we assume another ICMP
- * redirect will occur, this routine will reactivate, and then the hardware
- * address will be available in the cache.
- */
- if (redir && comparen(p->tcpout.i.ipdest,nnicmpsave,4)) {
- pc = getdlayer(nnicmpnew);
- if (pc != NULL)
- movebytes(p->tcpout.d.dest,pc,DADDLEN);
- }
- }
- }
- redir = 0; /* reset flag for next demux */
-
- } while ((t > time(NULL)) /* done yet? */
- && (time(NULL) >= start)); /* allow for wraparound of timer */
-
-
- return(nmux); /* will demux once, even for sleep(0) */
-
- } /* netsleep */
-
- #define ERROR_RESOURCE_ID 23237 /* BYU 2.4.16 */
- #define ERROR_RESOURCE_COUNT 52 /* BYU 2.4.16 */
-
- #if 0 /* BYU 2.4.16 */
- /************************************************************************/
- /* neterrstring
- * returns the string associated with a particular error number
- *
- * error number is formatted %4d at the beginning of the string
- */
- static char *errs[] = {" 0 Error unknown",
- " 100 ...", /* BYU 2.4.16 - strings moved to resource # 23237 */
- ""};
- #endif /* BYU 2.4.16 */
-
- static char errspace[80]; /* room for user-defined errors */
-
- char *neterrstring(errno)
- int errno;
- {
- int i;
- char s[10];
- Str255 ErrorString; /* BYU 2.4.16 */
-
- if (errno < 0)
- return(errspace);
-
- sprintf(s,"%4d",errno);
-
- #if 1 /* BYU 2.4.16 */
- for (i=1; i<=ERROR_RESOURCE_COUNT; i++) { /* BYU 2.4.16 */
- GetIndString(ErrorString,ERROR_RESOURCE_ID,i); /* BYU 2.4.16 */
- p2cstr(ErrorString); /* BYU 2.4.16 */
- if (!strncmp((char *) ErrorString,s,4)) /* BYU 2.4.16 */
- return((char *) ErrorString + 5); /* BYU 2.4.16 - pointer to error message */
- } /* BYU 2.4.16 */
-
- GetIndString(ErrorString,ERROR_RESOURCE_ID,1); /* BYU 2.4.16 */
- return((char *) ErrorString+5); /* BYU 2.4.16 - pointer to error message */
- #else /* BYU 2.4.16 */
- i = 0;
- do {
- if (!strncmp(errs[i],s,4))
- return(errs[i]+5); /* pointer to error message */
- i++;
-
- } while (*errs[i] || i > 100); /* until NULL found */
-
- return(errs[0]+5); /* error unknown */
- #endif /* BYU 2.4.16 */
- }
-
-